//package com.flow.server.common.utils;
//
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.github.pagehelper.util.StringUtil;
//import com.google.common.collect.Lists;
//import com.njxxted.activiti.common.constant.Constant;
//import com.njxxted.activiti.common.exception.CustomerException;
//import com.njxxted.activiti.modules.process.cmd.RollbackNodeCmd;
//import com.njxxted.activiti.modules.process.diagram.CustomProcessDiagramGenerator;
//import com.njxxted.activiti.modules.process.diagram.CustomProcessDiagramGeneratorI;
//import com.njxxted.activiti.modules.process.extend.dao.ExtendActHistoryDao;
//import com.njxxted.activiti.modules.process.extend.entity.ExtendActHistoryEntity;
//import de.odysseus.el.ExpressionFactoryImpl;
//import de.odysseus.el.util.SimpleContext;
//import org.activiti.bpmn.model.Process;
//import org.activiti.bpmn.model.*;
//import org.activiti.engine.*;
//import org.activiti.engine.history.HistoricActivityInstance;
//import org.activiti.engine.history.HistoricProcessInstance;
//import org.activiti.engine.history.HistoricTaskInstance;
//import org.activiti.engine.runtime.Execution;
//import org.activiti.engine.runtime.ProcessInstance;
//import org.activiti.engine.task.Task;
//import org.activiti.spring.SpringProcessEngineConfiguration;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import javax.el.ExpressionFactory;
//import javax.el.ValueExpression;
//import java.awt.*;
//import java.io.InputStream;
//import java.util.List;
//import java.util.*;
//import java.util.concurrent.CopyOnWriteArrayList;
//import java.util.stream.Collectors;
//
///**
// * 描述：工作流工具类
// * <p>
// * 作者：Ostrich Hu
// * 时间：2019/9/3 10:32 星期二
// */
//public class WorkflowUtils {
//
//    private static Logger logger = LoggerFactory.getLogger(WorkflowUtils.class);
//
//    private static RepositoryService repositoryService = (RepositoryService) ContextFactoryUtil.getBean("repositoryService");
//    private static HistoryService historyService = (HistoryService) ContextFactoryUtil.getBean("historyService");
//    private static RuntimeService runtimeService = (RuntimeService) ContextFactoryUtil.getBean("runtimeService");
//    private static TaskService taskService = (TaskService) ContextFactoryUtil.getBean("taskService");
//    private static ManagementService managementService = (ManagementService) ContextFactoryUtil.getBean("managementService");
//    private static ObjectMapper objectMapper = (ObjectMapper) ContextFactoryUtil.getBean("objectMapper");
////    private static ExtendActHistoryDao extendActHistoryDao = (ExtendActHistoryDao) ContextFactoryUtil.getBean("ExtendActHistoryDao");
//    private static SpringProcessEngineConfiguration peConfiguration = (SpringProcessEngineConfiguration) ContextFactoryUtil.getBean("springProcessEngineConfiguration");
//
//
//    /**
//     * 根据 BpmnModel 获取流程图像
//     *
//     * @param bpmnModel bpmn模型
//     * @return InputStream
//     */
//    public static InputStream getFlowImage(BpmnModel bpmnModel) {
//        //ProcessDiagramGenerator processDiagramGenerator = peConfiguration.getProcessDiagramGenerator();
//        CustomProcessDiagramGenerator customProcessDiagramGenerator =
//                (CustomProcessDiagramGenerator) peConfiguration.getProcessDiagramGenerator();
//        return customProcessDiagramGenerator.generateDiagram(bpmnModel, "png",
//                Collections.emptyList(), Collections.emptyList(),
//                "宋体", "宋体", "宋体",
//                null, 1.0);
//    }
//
//    /**
//     * 根据流程实例Id 查询 流程路径图
//     *
//     * @param instanceId 流程实例id
//     * @return
//     */
//    public static InputStream getFlowExecutionRouteImage(String instanceId) {
//        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
//                .processInstanceId(instanceId).singleResult();
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
//
//        List<HistoricActivityInstance> highLightedActivitiList = historyService.createHistoricActivityInstanceQuery()
//                .processInstanceId(instanceId).orderByHistoricActivityInstanceStartTime().asc().list();
//
//        //查询出历史
//        ExtendActHistoryEntity extendActHistoryEntity = new ExtendActHistoryEntity();
//        extendActHistoryEntity.setProcessInstanceId(instanceId);
////        extendActHistoryEntity.setTaskDefKey(flowNode.getId());
////        List<HistoryTaskInstanceEntity> historyTaskInstanceEntities = extendActHistoryDao.queryObjectByPidTid(instanceId, null);
////        List<ExtendActHistoryEntity> extendActHistories = extendActHistoryDao.queryListByBean(extendActHistoryEntity);
//        //去除退回的节点
////        extendActHistories.forEach(ext -> {
////            highLightedActivities.removeIf(act -> Constant.Flow.TASK_BACK.equals(ext.getOperateType()) ||
////                    Constant.Flow.TASK_BACK_2_START.equals(ext.getOperateType()));
////        });
//
//        // 高亮环节id集合
//        List<String> highLightedActivitis = new CopyOnWriteArrayList<>();
//        // 高亮线路id集合
//        List<String> highLightedFlows = getHighLightedFlows(highLightedActivitiList, processInstance.getProcessDefinitionId());
//        //获取高亮环节id
//        highLightedActivitiList.parallelStream().forEach(historicActivity -> {
//            String activityId = historicActivity.getActivityId();
//            String hisTaskId = historicActivity.getId();
////            HistoricActivityInstanceEntityImpl entity = (HistoricActivityInstanceEntityImpl) historicActivity;
////            logger.debug("节点名称[{}]任务id[{}]", entity.getActivityName(), hisTaskId);
//            highLightedActivitis.add(activityId);
//        });
//
//        //获取当前执行的节点id
//        Set<String> currIds = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).list()
//                .stream().map(Execution::getActivityId).collect(Collectors.toSet());
//
//        CustomProcessDiagramGeneratorI diagramGenerator = (CustomProcessDiagramGeneratorI) peConfiguration.getProcessDiagramGenerator();
//
//        Color[] colors = {Constant.Flow.COLOR_NORMAL, Constant.Flow.COLOR_CURRENT,
//                Constant.Flow.COLOR_REBACK, Constant.Flow.COLOR_SUSPPEND,
//                Constant.Flow.COLOR_CANCEL, Constant.Flow.COLOR_COMMON};
//
//        return diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis, highLightedFlows,
//                "黑体", "黑体", "黑体", null, 1.0, colors, currIds, instanceId);
//    }
//
//    /**
//     * 根据 BpmnModel 获取流程中的所有节点(不包含顺序流)
//     *
//     * @param bpmnModel bpmn模型
//     * @return List<Map < String, Object>>
//     */
//    public static List<Map<String, Object>> getAllNodeInProcess(BpmnModel bpmnModel) {
//        List<Map<String, Object>> nodeInfoList = new CopyOnWriteArrayList<>();
//        Process mainProcess = bpmnModel.getMainProcess();
//        List<FlowNode> flowNodeList = mainProcess.findFlowElementsOfType(FlowNode.class);
//        flowNodeList.parallelStream().forEach(flowNode -> {
//            Map<String, Object> nodeInfo = new HashMap<>();
//            List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
//            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
//            List<Map> targetMapList = new CopyOnWriteArrayList<>();
//            outgoingFlows.forEach(sequenceFlow -> {
//                Map<String, Object> targetMap = new HashMap<>();
//                FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
//                targetMap.put("targetName", targetFlowElement.getName());
//                targetMap.put("sequenceId", sequenceFlow.getId());
//                targetMap.put("targetId", targetFlowElement.getId());
//                targetMapList.add(targetMap);
//            });
//            //设置节点的变量信息
//            nodeInfo.put("outgoingTransitions", outgoingFlows);
//            nodeInfo.put("targetMapList", targetMapList);
//            nodeInfo.put("nodeKey", flowNode.getId());
//            nodeInfo.put("nodeType", convertType(flowNode));
//            nodeInfo.put("nodeName", flowNode.getName());
//            nodeInfo.put("x", graphicInfo.getX());
//            nodeInfo.put("y", graphicInfo.getY());
//            nodeInfo.put("width", graphicInfo.getWidth());
//            nodeInfo.put("height", graphicInfo.getHeight());
//            nodeInfoList.add(nodeInfo);
//        });
//        return nodeInfoList;
//    }
//
//    /**
//     * 根据节点Id取得当前节点的下一流向流程节点,如果Id为空则默认为首节点（条件路由则只返回符合条件的流向）
//     *
//     * @param defId       流程定义Id
//     * @param currNodeKey 当前流程节点
//     * @param elMap       流程变量el表达式集合
//     * @return
//     */
//    public static List<FlowNode> getNextNode(String defId, String currNodeKey, Map<String, Object> elMap) {
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(defId);
//        Process mainProcess = bpmnModel.getMainProcess();
//        List<FlowNode> flowNodes = new CopyOnWriteArrayList<>();
//        //1.获取流程所有节点
//        List<FlowNode> flowNodeList = mainProcess.findFlowElementsOfType(FlowNode.class);
//        if (null == currNodeKey) {
//            List<SequenceFlow> outgoingFlows = flowNodeList.get(0).getOutgoingFlows();
//            //startEvent节点
//            if (Constant.Flow.START_EVENT.equals(convertType(flowNodeList.get(0)))) {
//                List<FlowNode> flowDirection = getFlowDirection(outgoingFlows, elMap);
//                flowNodes.addAll(flowDirection);
//            }
//        } else {
//            //2.循环 flowNodeList 并判断出当前流程所处节点，然后得到当前节点实例，
//            flowNodeList.parallelStream().forEach(flowNode -> {
//                // 根据节点实例获取所有从当前节点出发的路径，然后根据路径获得下一个节点实例：
//                if (currNodeKey.equals(flowNode.getId())) {
//                    //获取流向下一节点的顺序流
//                    List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
//                    //判断分支流向
//                    List<FlowNode> flowDirection = getFlowDirection(outgoingFlows, elMap);
//                    flowNodes.addAll(flowDirection);
//                }
//            });
//        }
//        return flowNodes;
//    }
//
//    /**
//     * 获取当前执行节点的上一个已执行任务节点
//     *
//     * @param instanceId 流程实例id
//     * @return FlowElement
//     */
//    public static List<HistoricTaskInstance> getHisPreActivity(String instanceId) {
//        return historyService.createHistoricTaskInstanceQuery()
//                .processInstanceId(instanceId)
//                .orderByHistoricTaskInstanceStartTime()
//                .asc()
//                .list();
//    }
//
//    /**
//     * 获取当前执行节点的上一个已执行节点
//     *
//     * @param instanceId        流程实例id
//     * @param taskDefinitionKey 当前执行任务定义key
//     * @param isStarted         是否开始节点
//     * @return FlowElement
//     */
//    public static FlowNode getHasBeenDonePreNode(String instanceId, String taskDefinitionKey, boolean isStarted) {
//        //查询流程实例
//        ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
//        //根据流程实例获取流程定义模型
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
//        //根据流程定义模型获取所有节点的（有序）集合
//        Set<String> taskDefKeys = bpmnModel.getLocationMap().keySet();
//        List<String> taskDefKeyList = Lists.newArrayList(taskDefKeys);
//        //获取当前节点处于所有用户任务节点的索引位置
//        int index = taskDefKeyList.indexOf(taskDefinitionKey);
//        if (isStarted) {
//            //查找出第一个用户任务节点
//            return (FlowNode) bpmnModel.getFlowElement(taskDefKeyList.get(1));
//        } else {
//            //判断流程中是否有gate节点。如果有则通过流程历史处理，否则直接从定义模型中处理。
//            if (taskDefKeyList.indexOf("gate") == -1) {
//                //查找出当前节点的上一个节点
//                return (FlowNode) bpmnModel.getFlowElement(taskDefKeyList.get(index - 1));
//            } else {
//                //查询流程历史s
//                List<HistoricTaskInstance> hisPreActivityList = getHisPreActivity(instanceId);
//                if (hisPreActivityList.size() > 1) {
//                    //排除重复的历史节点
//                    List<String> finalTaskDefKeyList = Lists.newArrayList();
//                    hisPreActivityList.parallelStream().forEachOrdered(historicTaskInstance -> {
//                        boolean present = finalTaskDefKeyList.parallelStream()
//                                .filter(o -> o.equals(historicTaskInstance.getTaskDefinitionKey()))
//                                .findFirst().isPresent();
//                        if (!present) {
//                            finalTaskDefKeyList.add(historicTaskInstance.getTaskDefinitionKey());
//                        }
//                    });
//                    //找出当前节点所处的下标
//                    index = finalTaskDefKeyList.indexOf(taskDefinitionKey);
//                    return (FlowNode) bpmnModel.getFlowElement(finalTaskDefKeyList.get(index - 1));
//                } else {
//                    throw new ActivitiException("只有一个节点，不能进行驳回操作");
//                }
//            }
//        }
//    }
//
//    /***
//     * 回退
//     * @param currTaskId 当前节点id
//     * @param deleteReason 回退原因
//     * @param isStarted 是否退回到开始节点
//     */
//    public static void rollback(String currTaskId, String deleteReason, boolean isStarted) {
//        if (StringUtil.isEmpty(currTaskId)) {
//            throw new CustomerException("任务iD为空！");
//        }
//        Task currExecutionTask = getTaskById(currTaskId);
//        String processInstanceId = currExecutionTask.getProcessInstanceId();
//        String taskDefinitionKey = currExecutionTask.getTaskDefinitionKey();
//        //执行自定义的回退命令
//        RollbackNodeCmd rollbackNodeCmd = new RollbackNodeCmd(currTaskId);
//        rollbackNodeCmd.deleteReason = deleteReason;
//        rollbackNodeCmd.isStarted = isStarted;
//        rollbackNodeCmd.flowNode = getHasBeenDonePreNode(processInstanceId, taskDefinitionKey, isStarted);
//        managementService.executeCommand(rollbackNodeCmd);
//    }
//
//    /**
//     * 根据任务ID获取对应的流程实例
//     *
//     * @param taskId 任务ID
//     * @return
//     */
//    public static ProcessInstance getProcessInstanceByTaskId(String taskId) {
//        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
//                .processInstanceId(getTaskById(taskId).getProcessInstanceId()).singleResult();
//        if (processInstance == null) {
//            throw new CustomerException("流程实例未找到!");
//        }
//        return processInstance;
//    }
//
//    /**
//     * 各种情况的下级节点
//     *
//     * @param outgoingFlows 流向列表
//     * @param elMap         变量
//     * @return List<FlowElement>
//     */
//    private static List<FlowNode> getFlowDirection(List<SequenceFlow> outgoingFlows, Map<String, Object> elMap) {
//        List<FlowNode> flowElements = new CopyOnWriteArrayList<>();
//        outgoingFlows.parallelStream().forEach(outgoingFlow -> {
//            //1.获取顺序流流向流程的目标元素
//            FlowNode targetFlowElement = (FlowNode) outgoingFlow.getTargetFlowElement();
////            String targetFlowElementName = targetFlowElement.getName();
//            String targetFlowNodeType = convertType(targetFlowElement);
//            //2.判断目标元素类型
//            switch (targetFlowNodeType) {
//                case Constant.Flow.USER_TASK:
//                case Constant.Flow.END_EVENT:
//                    flowElements.add(targetFlowElement);
//                    break;
//                case Constant.Flow.EXCLUSIVE_GATEWAY:
//                    //根据流程变量判断网关条件的流向
//                    List<SequenceFlow> exlcusiveOutgoingFlows = targetFlowElement.getOutgoingFlows();
//                    exlcusiveOutgoingFlows.parallelStream().forEach(exlcusiveOutgoingFlow -> {
//                        //获取分支节点流向中的判断el表达式
//                        String conditionExpression = exlcusiveOutgoingFlow.getConditionExpression();
//                        for (String key : elMap.keySet()) {
//                            if (conditionExpression.contains(key)) {
//                                boolean condition = isCondition(key, conditionExpression, String.valueOf(elMap.get(key)));
//                                //判断该流向是否符合传入的参数条件且不是网关节点
//                                if (exlcusiveOutgoingFlow.getTargetFlowElement() instanceof ExclusiveGateway) {
//                                    //迭代获取
//                                    getFlowDirection(exlcusiveOutgoingFlows, elMap);
//                                } else if (condition) {
//                                    flowElements.add((FlowNode) exlcusiveOutgoingFlow.getTargetFlowElement());
//                                }
//                            }
//                        }
//                    });
//                    break;
//                case Constant.Flow.PARALLEL_GATEWAY:
//                    //并行网关
//                    List<SequenceFlow> parallelNodeOutgoingFlows = ((FlowNode) targetFlowElement).getOutgoingFlows();
//                    parallelNodeOutgoingFlows.parallelStream().forEach(parallelOutgoingFlow -> {
//                        flowElements.add((FlowNode) parallelOutgoingFlow.getTargetFlowElement());
//                    });
//                    break;
//            }
//        });
//
//        return flowElements;
//    }
//
//    /**
//     * 根据任务Id,查找当前任务
//     *
//     * @param taskId 任务Id
//     * @return
//     */
//    public static Task getTaskById(String taskId) {
//        return taskService.createTaskQuery().taskId(taskId).singleResult();
//    }
//
//    /**
//     * 将流程节点转为相对应节点名称字符串
//     *
//     * @param flowNode 流程节点
//     * @return string
//     */
//    private static String convertType(FlowNode flowNode) {
//        String type = "";
//        if (flowNode instanceof StartEvent) {
//            type = Constant.Flow.START_EVENT;
//        } else if (flowNode instanceof EndEvent) {
//            type = Constant.Flow.END_EVENT;
//        } else if (flowNode instanceof ExclusiveGateway) {
//            type = Constant.Flow.EXCLUSIVE_GATEWAY;
//        } else if (flowNode instanceof ParallelGateway) {
//            type = Constant.Flow.PARALLEL_GATEWAY;
//        } else if (flowNode instanceof UserTask) {
//            type = Constant.Flow.USER_TASK;
//        }
//        return type;
//    }
//
//    /**
//     * 根据key和value判断el表达式是否通过信息
//     *
//     * @param key          el表达式key信息
//     * @param elExpression el表达式信息
//     * @param elValue      el表达式传入值信息
//     * @return boolean
//     */
//    private static boolean isCondition(String key, String elExpression, String elValue) {
//        logger.debug(" el表达式key信息：{}\nel表达式信息：{}\nel表达式传入值信息:{}", key, elExpression, elValue);
//        ExpressionFactory factory = new ExpressionFactoryImpl();
//        SimpleContext context = new SimpleContext();
//        context.setVariable(key, factory.createValueExpression(elValue, String.class));
//        ValueExpression e = factory.createValueExpression(context, elExpression, boolean.class);
//        return (Boolean) e.getValue(context);
//    }
//
//    /**
//     * 获取需要高亮的线
//     *
//     * @param processDefId 流程定义id
//     * @param instances    流程节点历史
//     * @return
//     */
//    private static List<String> getHighLightedFlows(List<HistoricActivityInstance> instances, String processDefId) {
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
//        // 用以保存高亮的线flowId
//        List<String> highFlows = new ArrayList<>();
//        //1.对历史流程节点进行遍历
//        for (int i = 0; i < instances.size() - 1; i++) {
//            //2. 得到节点定义的详细信息
//            FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(instances.get(i).getActivityId());
//            //2.1 用以保存开始时间相同的节点
//            List<FlowNode> sameStartTimeNodes = new ArrayList<>();
//            FlowNode sameFlowNode1 = (FlowNode) bpmnModel.getFlowElement(instances.get(i + 1).getActivityId());
//            //3. 将后面第一个节点放在时间相同节点的集合里
//            sameStartTimeNodes.add(sameFlowNode1);
//            for (int j = 0; j < instances.size() - 1; j++) {
//                HistoricActivityInstance node1 = instances.get(j);// 后续第一个节点
//                HistoricActivityInstance node2 = instances.get(j + 1);// 后续第二个节点
//                if (Math.abs(node1.getStartTime().getTime() - node2.getStartTime().getTime()) < 200) {
//                    //3.1 如果第一个节点和第二个节点开始时间相同保存
//                    FlowNode sameFlowNode2 = (FlowNode) bpmnModel.getFlowElement(node2.getId());
//                    sameStartTimeNodes.add(sameFlowNode2);
//                } else {
//                    //3.2 有不相同跳出循环
//                    break;
//                }
//            }
//            //4. 取出节点的所有出去的线
//            List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
//            outgoingFlows.forEach(outgoingFlow -> {
//                //4.1 对所有的线进行遍历
//                FlowNode targetFlowNode = (FlowNode) outgoingFlow.getTargetFlowElement();
//                //4.2 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
//                if (sameStartTimeNodes.contains(targetFlowNode)) {
//                    highFlows.add(outgoingFlow.getId());
//                }
//            });
//        }
//        return highFlows;
//    }
//}
